using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using System.Text.RegularExpressions;
using System.Net;
using System.Web;

namespace BoldBrick.SharePoint.CommonControls.Utils
{
	public static class UrlHelper
	{
		#region Query String

		/// <summary> 
		/// Adds query string to the original url 
		/// </summary> 
		/// <param name="originalURL">Original url</param> 
		/// <param name="newQueryString">Query string to add</param>                            
		/// <returns>New URL</returns> 
		public static string AddQueryString(string originalURL, string newQueryString)
		{
			// declare the returned value 
			string totalURLAndQueryString;
			string justURL = originalURL;

			// check the existence of the query strring 
			if (string.IsNullOrEmpty(newQueryString))
				return originalURL;

			// determine there is an original query string 
			int positionOriginalQueryString = originalURL.IndexOf('?');
			bool hasOriginalQueryString = positionOriginalQueryString > -1;

			if (hasOriginalQueryString)
				justURL = justURL.Remove(positionOriginalQueryString, justURL.Length - positionOriginalQueryString);


			// if the original url doesn't have the query string just add the new one 
			if (!hasOriginalQueryString)
				totalURLAndQueryString = justURL + "?" + newQueryString;

			else // do some logic to append or replace it 
			{
				// get the original query string 
				string originalQueryString = originalURL.Substring(positionOriginalQueryString + 1, originalURL.Length - positionOriginalQueryString - 1);

				// now must determine there is the same query string id's and if so then replace it, otherwise add it

				//List<string> originalStrings = new List<string>(originalQueryString.Split(new char[] { '=', '&' }));

				//List<string> newStrings = new List<string>(newQueryString.Split(new char[] { '=', '&' }));

				Dictionary<string, string> valuesOriginal = GetValues(originalQueryString);
				Dictionary<string, string> valuesNew = GetValues(newQueryString);

				StringBuilder sb = new StringBuilder();

				foreach (string valueID in valuesOriginal.Keys)
				{
					if (sb.Length > 0)
					{
						sb.Append("&");
					}

					if (valuesNew.ContainsKey(valueID))
					{
						sb.AppendFormat("{0}={1}", valueID, valuesNew[valueID]);
						valuesNew.Remove(valueID);
					}
					else
					{
						sb.AppendFormat("{0}={1}", valueID, valuesOriginal[valueID]);
					}
				}

				foreach (string valueID in valuesNew.Keys)
				{
					if (sb.Length > 0)
					{
						sb.Append("&");
					}
					sb.AppendFormat("{0}={1}", valueID, valuesNew[valueID]);
				}

				string urlNew = string.Format("{0}?{1}", justURL, sb);
				return urlNew;

                #region Original code ???
                // find the conflict query string id's, with the same id's                              

                //Predicate<string> hasTheSameQueryStringID = delegate(string queryStringID)
                //                                                {
                //                                                    return (originalStrings.Contains(queryStringID));
                //                                                };
                //List<string> conflicts = newStrings.FindAll(hasTheSameQueryStringID);

                //// now go through conflicts and replace them with the new values 
                //for (int i = 0; i < conflicts.Count; i += 2)
                //{
                //    // find the start id and mark the position 
                //    int positionIdentifier = originalQueryString.IndexOf(conflicts[i]);
                //    if (positionIdentifier > -1)
                //    {
                //        int positionEquals = originalQueryString.IndexOf('&', positionIdentifier);

                //        if (positionEquals > -1)

                //            originalQueryString = originalQueryString.Remove(positionIdentifier, positionEquals - positionIdentifier);

                //        else
                //            if (positionIdentifier.Equals(0))
                //            {
                //                // V puvodni implementaci positionIdentifier.Equals(0) nebylo osetreno..
                //                originalQueryString =
                //                    originalQueryString.Remove(positionIdentifier, originalQueryString.Length - positionIdentifier);
                //            }
                //            else
                //            {
                //                originalQueryString =
                //                    originalQueryString.Remove(positionIdentifier - 1, originalQueryString.Length - positionIdentifier + 1);
                //            }
                //    }

                //}

                //// add new id's 
                //if (originalQueryString.StartsWith("&"))
                //    originalQueryString = originalQueryString.Substring(1, originalQueryString.Length - 1);

                //totalURLAndQueryString = justURL + "?" + originalQueryString + (originalQueryString.Length > 0 ? "&" : "") + newQueryString;
                #endregion

            }

			return totalURLAndQueryString;
		}

		private static Dictionary<string, string> GetValues(string queryString)
		{
			Dictionary<string, string> values = new Dictionary<string, string>();
			
			// split to parts
			string[] queryStringParts = queryString.Split('&');
			foreach (string queryStringPart in queryStringParts)
			{
				// split to name and value
				string[] nameValue = queryStringPart.Split('=');
				
				// save name and value
				string key = nameValue[0].ToLower(); // Vsechny klice do lowercase, QS je case insensitive. Bez tohoto se duplikovaly klice s ruznymi case.
				if ( nameValue.Length == 1 )
					values[key] = string.Empty;
				else if ( nameValue.Length == 2 )
					values[key] = nameValue[1];
			}

			//for (int i = 0; i < list.Count; i += 2)
			//{
			//    string originalID = list[i];
			//    string originalValue = list[i + 1];
			//    values[originalID] = originalValue;
			//}
			return values;
		}
		
		public static string GetQueryParameter(string url, string queryParameterName)
		{
			return GetQueryParameter(
                new Uri(url), queryParameterName);
		}

        public static string GetQueryParameter(Uri uri, string queryParameterName)
        {
            NameValueCollection query = HttpUtility.ParseQueryString(uri.Query);
            string value = query[queryParameterName];
            return value;
        }

		#endregion

		#region Manipulation

		/// <summary>
		/// This method combines part of the URL
		/// </summary>
		/// <param name="parts">Parts of the URL</param>
		/// <returns>Returns combined URL</returns>
		public static string CombineURLPath(params object[] parts)
		{
			StringBuilder sb = new StringBuilder();
			foreach (object obj in parts)
			{
				if (sb.Length == 0)
					sb.Append(obj);
				else
				{
					if (sb[sb.Length - 1] == '/')
						sb.Remove(sb.Length - 1, 1);

					string path = obj.ToString();
					if (!path.StartsWith("/"))
						sb.Append("/");

					sb.Append(path);
				}
			}
			return sb.ToString();
		}
		
		/// <summary>
		/// Extracts server url. From "http://localhost:40045/Folder1/Page1.aspx" extracts "http://localhost:40045"
		/// </summary>
		/// <param name="url">Source URL</param>
		/// <returns>Returns server url</returns>
		public static string GetServerPath(string url)
		{
			const string pattern = "https*://[^/]*";
			
			Match match = Regex.Match(url, pattern);
			if (!match.Success)
				return null;

			return match.Value;
		}

		/// <summary>
		/// Zkontroluje, zda je specifikovany string validni domenou (napr. www.boldbrick.com, seznam.cz, atd.)
		/// </summary>
		/// <param name="domain"></param>
		/// <returns></returns>
		public static bool IsValidDomain(string domain)
		{
			if (string.IsNullOrEmpty(domain))
				return false;

			Regex regex = new Regex(@"^([a-z][a-z0-9\-]+(\.|\-*\.))+[a-z]{2,6}$");
			bool isValid = regex.IsMatch(domain.ToLower());

			return isValid;
		}

        public static string GetServerPathForCurrentDirectory(string url)
        {
            if (url.Contains("?"))
                url = url.Substring(0, url.IndexOf("?"));
            if (url.EndsWith("/"))
                return url;

            string[] parts = url.Split('/');
            if (!parts[parts.Length - 1].Contains("."))
                return url;

            string currentUrlPath = url.Substring(0, url.LastIndexOf("/"));

            return currentUrlPath;
        }

        public static string GetServerPathForParrentDirectory(string url)
        {
            string currentPath = GetServerPathForCurrentDirectory(url);
            if (!currentPath.Contains("/"))
                return string.Empty;

            string parentPath = currentPath.Substring(0, currentPath.LastIndexOf("/"));

            return parentPath;
        }

        /// <summary>
        /// This methods converts http links to https links and vice versa
        /// </summary>
        /// <param name="originalUrl">original url</param>
        /// <returns></returns>
        public static string ConvertProtocol(string originalUrl)
        {
            string otherTargetUrl = originalUrl;
            if (otherTargetUrl.StartsWith("http://"))
                otherTargetUrl = otherTargetUrl.Replace("http://", "https://");
            else if (otherTargetUrl.StartsWith("https://"))
                otherTargetUrl = otherTargetUrl.Replace("https://", "http://");

            return otherTargetUrl;
        }

		#endregion

        /// <summary>
        /// This method is only for development
        /// </summary>
        /// <returns></returns>
        public static NetworkCredential GetCredentials()
        {
            return new NetworkCredential("name", "pass", "domain");
        }

		public static string GetPageURL(HttpContext httpContext)
		{
			string pageUrl = httpContext.Request.Url.Segments[httpContext.Request.Url.Segments.Length - 1];
			pageUrl += httpContext.Request.Url.Query;
			return pageUrl;
		}

		/// <summary>
		/// Ze zadane url vytahne domenu v pozadovanem formatu (plus port, protocol, atd).
		/// </summary>
		/// <param name="url"></param>
		/// <param name="domainParts"></param>
		/// <returns></returns>
		public static string GetDomain(string url, DomainParts domainParts)
		{
			if (string.IsNullOrEmpty(url))
				return null;

			try
			{
				Uri uri = new Uri(url);
				string ret = "";

				if ((domainParts & DomainParts.Protocol) == DomainParts.Protocol)
				{
					ret += uri.Scheme + "://";
				}

				ret += uri.Host;

				if ((domainParts & DomainParts.Port) == DomainParts.Port)
				{
					ret += ":" + uri.Port;
				}

				return ret;
			}
			catch (Exception ex)
			{
				throw new Exception("Error while UrlHelper.GetDomain('{0}')", ex);
			}
		}

		[Flags]
		public enum DomainParts
		{
			Protocol = 1,
			Domain = 2,
			Port = 4
		}

    }
}